#ifndef RAIS_BS818A_2_PARALLEL_H
#define RAIS_BS818A_2_PARALLEL_H

/*
	Rais_BS818A_2_Parallel: BS818A_2 芯片的并行方式8键实现库.
		用于七星虫(LY_S5003) 8触摸按钮元件.
	
	Created: 2020.7.5
	By Raiscies.
	
	class: BS818A_2_Parallel / EightButtons / LY_S5003
	Methods:
		uint8_t get()
		bool isTouched()
		uint8_t get_ignore_B3()
		bool isTouched_ignore_B3()
		uint8_t operator()()
		wait_touched<F>(uint8_t key, F func)
		wait_touched(uint8_t key = 0)
		wait_released<F>(uint8_t key, F func)
		wait_released(uint8_t key = 0)
		wait_touched_until_released<F>(uint8_t key, F func)
	
*/

#include "Arduino.h"

namespace rais{

using len_t = unsigned int;

class BS818A_2_Parallel {
	
	public:
	const uint8_t PIN_B0, PIN_B1, PIN_B2, PIN_B3;
	
	BS818A_2_Parallel(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3 = 255)
	: PIN_B0(b0), PIN_B1(b1), PIN_B2(b2), PIN_B3(b3) {
		pinMode(PIN_B0, INPUT);
		pinMode(PIN_B1, INPUT);
		pinMode(PIN_B2, INPUT);
		if(PIN_B3 != 255) pinMode(PIN_B3, INPUT);
	}
	
	uint8_t get() const{
		return digitalRead(PIN_B3) ? 0 : (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1;
	}
	
	bool isTouched() const{
		return digitalRead(PIN_B3) ? 0 : 1;
	}
	
	uint8_t get_ignore_B3() const{
		uint8_t state = (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111);
		if(state == 0) return 0;
		else return state + 1;
	}
	
	bool isTouched_ignore_B3() const{
		return (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) == 1 ? false : true;
	}
	
	uint8_t operator()() const{
		return get();
	}
	
	template <typename F>	//make key = 0 to listen all keys.
	void wait_touched(uint8_t key, F func) const{
		if(!key || key > 8) while(digitalRead(PIN_B3));
		else 				while(digitalRead(PIN_B3) || key != (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);
		func();
	}						//ignore 'key' arg to listen all keys.
	void wait_touched(uint8_t key = 0) const{
		if(!key || key > 8) while(digitalRead(PIN_B3));
		else				while(digitalRead(PIN_B3) || key != (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);
	}
	
	//return key touched time(ms)
	template <typename F>
	len_t wait_released(uint8_t key, F func) const{
		len_t timelen;
		if(!key || key > 8){
			while(digitalRead(PIN_B3));		//hasn't been touched
			timelen = millis();
			while(!digitalRead(PIN_B3));	//wait until released
		}else {
			while( digitalRead(PIN_B3) || key != (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);	//hasn't been touched 
			timelen = millis();
			while(!digitalRead(PIN_B3) && key == (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);	//wait unril released
		}
		timelen = millis() - timelen;
		func();
		return timelen;
	}
	
	//return key touched time(ms)
	len_t wait_released(uint8_t key = 0) const{
		len_t startTimeStamp;
		if(!key || key > 8){
			while(digitalRead(PIN_B3));		//hasn't been touched
			startTimeStamp = millis();
			while(!digitalRead(PIN_B3));	//wait until released
		}else {
			while( digitalRead(PIN_B3) || key != (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);	//hasn't been touched 
			startTimeStamp = millis();
			while(!digitalRead(PIN_B3) && key == (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);	//wait until released
		}
		return millis() - startTimeStamp;
	}
	
	template <typename F>			//make key = 0 to listen all keys.
	void wait_touched_until_released(uint8_t key, F func) const{
		if(!key || key > 8){
			while(digitalRead(PIN_B3));		//hasn't been touched
			func();
			while(!digitalRead(PIN_B3));	//wait until released
		}else {
			while( digitalRead(PIN_B3) || key != (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);	//hasn't been touched 
			func();
			while(!digitalRead(PIN_B3) && key == (~((digitalRead(PIN_B2) << 2) | (digitalRead(PIN_B1) << 1) | digitalRead(PIN_B0)) & B111) + 1);	//wait until released
		}
	}
};	//class BS818A_2_Parallel

using EightButtons	= BS818A_2_Parallel;
using LY_S5003		= BS818A_2_Parallel;

}	//namespace rais
	
#endif